package org.lora.core.mybatis;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.builder.StaticSqlSource;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.MappedStatement.Builder;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.mapping.ResultMapping;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSession;

/**
 * <p>
 * 类名:SqlExcutePlugin
 * </p>
 * 描述:直接执行SQL<br>
 * 创建时间:2016年7月26日 下午2:33:02<br>
 * 
 * @author Bladnir@outlook.com<br>
 *         修改历史:<br>
 *         2016年7月26日 Bladnir 创建<br>
 */
public class SqlExcutePlugin {

	private final SqlSession sqlSession;
	private final Configuration configuration;

	/**
	 * 构造方法
	 * 
	 * @param sqlSession
	 */
	public SqlExcutePlugin(SqlSession sqlSession) {
		this.sqlSession = sqlSession;
		this.configuration = sqlSession.getConfiguration();
	}

	/**
	 * 执行SQL语句
	 * 
	 * @param sql
	 * @return
	 */
	public Object sqlExcute(String sql) {
		Object value = null;

		if (sql.startsWith("select") || sql.startsWith("SELECT")) {// 查询
			String msId = this.select(sql);
			value = sqlSession.selectList(msId);
		} else if (sql.startsWith("delete") || sql.startsWith("DELETE")) {// 删除
			String msId = this.delete(sql);
			value = sqlSession.delete(msId);
		} else if (sql.startsWith("update") || sql.startsWith("UPDATE")) {// 更新
			String msId = this.update(sql);
			value = sqlSession.update(msId);
		} else if (sql.startsWith("insert") || sql.startsWith("INSERT")) {// 插入
			String msId = this.insert(sql);
			value = sqlSession.insert(msId);
		}

		return value;
	}

	/**
	 * 创建MSID
	 *
	 * @param sql
	 *            执行的sql
	 * @param sql
	 *            执行的sqlCommandType
	 * @return
	 */
	private String newMsId(String sql, SqlCommandType sqlCommandType) {
		StringBuilder msIdBuilder = new StringBuilder(sqlCommandType.toString());
		msIdBuilder.append(".").append(sql.hashCode());
		return msIdBuilder.toString();
	}

	/**
	 * 是否已经存在该ID
	 *
	 * @param msId
	 * @return
	 */
	private boolean hasMappedStatement(String msId) {
		return configuration.hasStatement(msId, false);
	}

	/**
	 * 创建一个查询的MS
	 *
	 * @param msId
	 * @param sqlSource
	 *            执行的sqlSource
	 * @param resultType
	 *            返回的结果类型
	 */
	private void newSelectMappedStatement(String msId, SqlSource sqlSource, final Class<?> resultType) {

		Builder bulider = new MappedStatement.Builder(configuration, msId, sqlSource, SqlCommandType.SELECT);

		List<ResultMap> resultList = new ArrayList<>();

		ResultMap resultMap = new ResultMap.Builder(configuration, "defaultResultMap", resultType, new ArrayList<ResultMapping>(0)).build();
		resultList.add(resultMap);

		MappedStatement ms = bulider.resultMaps(resultList).build();

		// 缓存
		configuration.addMappedStatement(ms);
	}

	/**
	 * 创建一个简单的MS
	 *
	 * @param msId
	 * @param sqlSource
	 *            执行的sqlSource
	 * @param sqlCommandType
	 *            执行的sqlCommandType
	 */
	private void newUpdateMappedStatement(String msId, SqlSource sqlSource, SqlCommandType sqlCommandType) {

		Builder bulider = new MappedStatement.Builder(configuration, msId, sqlSource, sqlCommandType);

		List<ResultMap> resultList = new ArrayList<>();

		ResultMap resultMap = new ResultMap.Builder(configuration, "defaultResultMap", int.class, new ArrayList<ResultMapping>(0)).build();
		resultList.add(resultMap);

		MappedStatement ms = bulider.resultMaps(resultList).build();

		// 缓存
		configuration.addMappedStatement(ms);
	}

	private String select(String sql) {
		String msId = newMsId(sql, SqlCommandType.SELECT);
		if (hasMappedStatement(msId)) {
			return msId;
		}
		StaticSqlSource sqlSource = new StaticSqlSource(configuration, sql);
		newSelectMappedStatement(msId, sqlSource, Map.class);
		return msId;
	}

	private String insert(String sql) {
		String msId = newMsId(sql, SqlCommandType.INSERT);
		if (hasMappedStatement(msId)) {
			return msId;
		}
		StaticSqlSource sqlSource = new StaticSqlSource(configuration, sql);
		newUpdateMappedStatement(msId, sqlSource, SqlCommandType.INSERT);
		return msId;
	}

	private String update(String sql) {
		String msId = newMsId(sql, SqlCommandType.UPDATE);
		if (hasMappedStatement(msId)) {
			return msId;
		}
		StaticSqlSource sqlSource = new StaticSqlSource(configuration, sql);
		newUpdateMappedStatement(msId, sqlSource, SqlCommandType.UPDATE);
		return msId;
	}

	private String delete(String sql) {
		String msId = newMsId(sql, SqlCommandType.DELETE);
		if (hasMappedStatement(msId)) {
			return msId;
		}
		StaticSqlSource sqlSource = new StaticSqlSource(configuration, sql);
		newUpdateMappedStatement(msId, sqlSource, SqlCommandType.DELETE);
		return msId;
	}

}
